﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using Golos.Users.UserCache;
using Golos.Web.Utils;

namespace Golos.Web.handlers
{
    public class LoginHandler : HandlerBase
    {
        public LoginHandler(HttpContext httpContext)
            : base(httpContext)
        {
        }
        public override void Handle()
        {
            string net = GetQueryParam("net");
            
            try
            {
                switch (net)
                {
                    case "vk":
                        authVK();
                        break;
                    case "fb":
                        authFB();
                        break;
                    case "tw":
                        authTW();
                        break;
                    case "mailru":
                        authMailRu();
                        break;
                    default:
                        authOther();
                        break;
                }   
            }
            catch (Exception e)
            {
                LogClass.WriteErrorEntry(e.ToString());
            }
        }

        
        private void authOther()
        {
            LogClass.WriteErrorEntry("Мне непонятно через что аутентифицироваться.");

            _httpContext.Response.Redirect("/Default.aspx");
        }

        private void authVK()
        {
            LogClass.WriteInfoEntry("Аутентификация vkontate.ru");

            //Encoding encoding = Encoding.UTF8;

            string uid = GetQueryParam("uid");
            string hash = GetVKHash(_httpContext.Request.Cookies["vk_app_" + Settings.ReadFromFile().VkAppId].Value);
            string first_name = GetQueryParam("first_name");
            string last_name = GetQueryParam("last_name");

            string name = last_name + " " + first_name;

            if (CheckVKHash(hash, GetVKSig()))
            {
                LogClass.WriteInfoEntry("Проверка хэша Вконтакте прошла успешно.");

                try
                {
                    RegisterUser(UserIdType.VK, uid, name);
                }
                catch (Exception e)
                {
                    _httpContext.Response.Write("{ \"error\": \"Не удалось авторизоваться.\" }");
                    LogClass.WriteErrorEntry("Не удалось зарегистрировать пользователя VK. [uid=" + uid + ", name=" + name + ", hash=" + hash + "]");
                    LogClass.WriteErrorEntry(e.ToString());
                }
            }
            else
            {
                _httpContext.Response.Write("{ \"error\": \"Не удалось проверить хэш.\" }");
                LogClass.WriteErrorEntry("Не удалось проверить хэш VK. [uid=" + uid + ", name=" + name + ", hash=" + hash + "]");
            }
        }

        private void authFB()
        {
            LogClass.WriteInfoEntry("Аутентификация facebook.com");

            string uid = GetQueryParam("uid");
            string first_name = GetQueryParam("first_name");
            string last_name = GetQueryParam("last_name");
            //string email = GetQueryParam("email");
            //string gender = GetQueryParam("gender");

            string name = last_name + " " + first_name;
            string hash = _httpContext.Request.Cookies["fbsr_" + Settings.ReadFromFile().FbAppId].Value;

            if (CheckFbHash(hash))
            {
                LogClass.WriteInfoEntry("Проверка хэша Facebook прошла успешно.");

                try
                {
                    RegisterUser(UserIdType.FB, uid, name);
                }
                catch (Exception e)
                {
                    _httpContext.Response.Write("{ \"error\": \"Не удалось авторизоваться.\" }");
                    LogClass.WriteErrorEntry("Не удалось зарегистрировать пользователя FB. [uid=" + uid + ", name=" + name + "]");
                    LogClass.WriteErrorEntry(e.ToString());
                }
            }
            else
            {
                _httpContext.Response.Write("{ \"error\": \"Не удалось проверить хэш.\" }");
                LogClass.WriteErrorEntry("Не удалось проверить хэш FB. [uid=" + uid + ", name=" + name + "]");
            }
        }
        
        private void authTW()
        {
            LogClass.WriteInfoEntry("Аутентификация twitter.com");
            string uid = GetQueryParam("uid");
            string hash = _httpContext.Request.Cookies["twitter_anywhere_identity"].Value.Split(new char[] { ':' })[1];
            string name = GetQueryParam("name");

            if (CheckTwHash(uid, hash))
            {
                LogClass.WriteInfoEntry("Проверка хэша Twitter прошла успешно.");

                try
                {
                    RegisterUser(UserIdType.TW, uid, name);
                }
                catch (Exception e)
                {
                    _httpContext.Response.Write("{ \"error\": \"Не удалось авторизоваться.\" }");
                    LogClass.WriteErrorEntry("Не удалось зарегистрировать пользователя TW. [uid=" + uid + ", name=" + name + ", hash=" + hash + "]");
                    LogClass.WriteErrorEntry(e.ToString());
                }
            }
            else
            {
                _httpContext.Response.Write("{ \"error\": \"Не удалось проверить хэш.\" }");
                LogClass.WriteErrorEntry("Не удалось проверить хэш TW. [uid=" + uid + ", name=" + name + ", hash=" +hash +"]");
            }
        }

        private void authMailRu()
        {
            LogClass.WriteInfoEntry("Аутентификация через mail.ru");
            string uid = GetQueryParam("uid");
            string hash = GetQueryParam("hash");
            string name = GetQueryParam("first_name");
            string last_name = GetQueryParam("last_name");
            string email = GetQueryParam("email");
        }
         

        private bool CheckTwHash(string uid, string hashFromUser)
        {
            string realHash = uid + Settings.ReadFromFile().TwSecretKey;

            if (hashFromUser == Encrypter.GetSHA1Hash(realHash))
            {
                return true;
            }
            return false;
        }

        private bool CheckFbHash(string hash)
        {
            LogClass.WriteDebugEntry("fb hash=" + hash);
            string[] list = hash.Split(new char[] { '.' }, 2, StringSplitOptions.RemoveEmptyEntries);

            string sig = list[0];

            LogClass.WriteDebugEntry("fb sig=" + sig);
            string expected_sig = Encrypter.HMACSHA256(list[1], Settings.ReadFromFile().FbSecretKey);

            if (sig == expected_sig)
            {
                return true;
            }
            return false;
        }

        private bool CheckVKHash(string stringFromUser, string sigFromUser)
        {
            string hash = Encrypter.GetMD5Hash(stringFromUser + Settings.ReadFromFile().VkSecretKey);

            if (sigFromUser == hash)
            {
                return true;
            }
            return false;
        }


        private string GetVKHash(string cookie)
        {
            cookie = cookie.Substring(0, cookie.IndexOf("&sig"));
            cookie = cookie.Replace("&", "");
            
            return cookie;
        }

        private string GetVKSig()
        {
            string cookie = _httpContext.Request.Cookies["vk_app_" + Settings.ReadFromFile().VkAppId].Value;
            cookie = cookie.Substring(cookie.IndexOf("sig=") + 4);
            
            return cookie;
        }

        private void RegisterUser(UserIdType userIdType, string uid, string name)
        {
            Token secretToken = TokenUtils.CheckSecretCookie(_httpContext.Request.Cookies);
            if (secretToken != null)
            {
                //TODO: attach user;
            }

            Guid userId = UsersClient.RegisterUser(name, userIdType, uid);

            Token token = new Token(userId, DateTime.Now.AddDays(Settings.ReadFromFile().TokenLifeTime));
            LogClass.WriteDebugEntry("User: " + token.User + " [net=" + userIdType + ",uid=" + uid + ",name=" + name + "]");

            TokenUtils.ToCookies(_httpContext.Response.Cookies, token);

            _httpContext.Response.Write("{ \"success\": \"Пользователь авторизован.\" }");
        }
    }
}